from flask import Flask, request, jsonify
from selenium.common.exceptions import TimeoutException, NoSuchElementException
from engine.driver_manager import driver_manager, BrowserType
from engine.step_executor import executor, StepStatus
import time
import uuid
import os

app = Flask(__name__)

# 存储测试执行状态
test_executions = {}

# 浏览器类型映射
browser_type_map = {
    "chrome": BrowserType.CHROME,
    "firefox": BrowserType.FIREFOX,
    "edge": BrowserType.EDGE,
    "safari": BrowserType.SAFARI
}


def execute_test_steps(driver_id, steps):
    """执行测试步骤"""
    results = []
    
    for step in steps:
        # 转换步骤格式以匹配执行器要求
        formatted_step = {
            "id": step.get("id"),
            "type": step.get("action"),
            "locator": {
                "by": "xpath",
                "value": step.get("locator")
            },
            "url": step.get("url"),
            "text": step.get("text"),
            "expected_text": step.get("expected_text"),
            "timeout": step.get("timeout", 10),
            "stop_on_failure": step.get("stop_on_failure", True)
        }
        
        # 执行步骤
        step_result = executor.execute_step(driver_id, formatted_step)
        results.append(step_result)
        
        # 如果步骤失败且设置了停止执行，则终止后续步骤
        if step_result["status"] == StepStatus.FAILED.value and formatted_step["stop_on_failure"]:
            break
            
    return results

@app.route('/api/test/execute', methods=['POST'])
def execute_test():
    """接收测试执行请求并执行"""
    test_id = request.json.get("test_id")  # 新增：前端可传 test_id
    data = request.json
    driver_id = None
    
    # 检查是否是模拟测试请求
    is_mock_test = False
    if data and isinstance(data.get("steps"), list):
        for step in data["steps"]:
            if step.get("action") == "mock_step":
                is_mock_test = True
                break
    
    # 如果是模拟测试，直接返回成功响应，跳过实际浏览器操作
    if is_mock_test:
        print("检测到模拟测试请求，跳过实际浏览器操作")
        if not test_id:
            test_id = "mock_" + str(int(time.time()))
        
        # 创建模拟的测试结果
        mock_results = []
        for i, step in enumerate(data.get("steps", [])):
            mock_results.append({
                "id": step.get("id", f"step_{i+1}"),
                "type": step.get("action", "unknown"),
                "status": "success",
                "message": "模拟测试步骤成功执行",
                "duration": 0.1,
                "timestamp": time.time()
            })
        
        # 更新测试执行记录
        test_executions[test_id] = {
            "status": "success",
            "start_time": time.time(),
            "end_time": time.time(),
            "duration": 0.1,
            "results": mock_results,
            "test_case": data.get("test_case"),
            "driver_id": None,
            "is_mock": True
        }
        
        return jsonify({
            "test_id": test_id,
            "status": "success",
            "message": "模拟测试执行成功",
            "results": mock_results
        })

    # 正常测试执行逻辑（原始代码）
    try:
        # 如果 test_id 已存在，则复用 driver
        if test_id and test_id in test_executions and test_executions[test_id]["driver_id"]:
            driver_id = test_executions[test_id]["driver_id"]
            # 不新建 driver
        else:
            # 如果 test_id不存在，则新建 driver，并用这个 test_id 关联
            if not test_id:
                test_id = str(uuid.uuid4())
            # 获取浏览器类型
            browser = data.get("browser", "chrome")
            browser_type = browser_type_map.get(browser.lower(), BrowserType.CHROME)
            # 创建WebDriver实例
            driver_id = driver_manager.create_driver(
                browser_type=browser_type,
                headless=data.get("headless", False),
                window_size=(1920, 1080)
            )
            # 初始化测试执行记录
            test_executions[test_id] = {
                "status": "running",
                "start_time": time.time(),
                "results": None,
                "test_case": data.get("test_case"),
                "driver_id": driver_id
            }

        # 执行测试步骤
        results = execute_test_steps(driver_id, data.get("steps", []))

        # 计算总体结果
        overall_status = "success"
        for step in results:
            if step["status"] == StepStatus.FAILED.value:
                overall_status = "failure"
                break

        # 更新测试执行记录
        test_executions[test_id].update({
            "status": overall_status,
            "end_time": time.time(),
            "results": results,
            "duration": time.time() - test_executions[test_id].get("start_time", time.time())
        })

        # 浏览器关闭逻辑
        if driver_id and not data.get("keep_browser_open", False):
            driver_manager.quit_driver(driver_id)
            test_executions[test_id]["driver_id"] = None

        return jsonify({
            "test_id": test_id,
            "status": test_executions[test_id]["status"],
            "message": "测试执行已启动",
            "results": test_executions[test_id].get("results")
        })
    except Exception as e:
        print(f"测试执行过程中发生错误: {str(e)}")
        # 确保即使发生错误，也返回一个有效的JSON响应
        if not test_id:
            test_id = "error_" + str(int(time.time()))
        
        error_result = {
            "status": "error",
            "message": f"测试执行失败: {str(e)}",
            "error_type": type(e).__name__
        }
        
        test_executions[test_id] = {
            "status": "error",
            "start_time": time.time(),
            "end_time": time.time(),
            "duration": 0,
            "results": [error_result],
            "test_case": data.get("test_case"),
            "driver_id": driver_id
        }
        
        # 尝试清理资源
        if driver_id:
            try:
                driver_manager.quit_driver(driver_id)
            except:
                pass
        
        return jsonify({
            "test_id": test_id,
            "status": "error",
            "message": f"测试执行失败: {str(e)}",
            "results": [error_result]
        }), 500
@app.route('/api/test/status/<test_id>', methods=['GET'])
def get_test_status(test_id):
    """获取测试执行状态"""
    if test_id not in test_executions:
        return jsonify({"error": "测试ID不存在"}), 404
        
    return jsonify(test_executions[test_id])

if __name__ == '__main__':
    # 启动Flask应用
    app.run(host='0.0.0.0', port=5000, debug=True)
